// 版权所有2010 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package cmplx

import "math"

// 下面的原始C代码、长注释和常量
// 来自http:
// go代码是原始C.
// 
// Cephes数学库发行版2.8:2000年6月
// 版权所有1984、1987、1989、1992、2000作者Stephen L.Moshier 
// 
// http:
// 本档案中的一些软件可能来自《数学函数的方法和程序》（Prentice Hall或Simon&Schuster 
// International，1989）一书，也可能来自Cephes数学图书馆，一本
// 商业产品。无论哪种情况，它都是作者的版权。
// 您在这里看到的内容可以免费使用，但不提供任何支持或保证。
// 
// 本书中两个已知的印刷错误在这里的
// 伽马函数和不完整的beta 
// 积分的源代码列表中修复。
// 
// Stephen L.Moshier 
// moshier@na-网。奥尔。gov 

// 复圆弧正弦
// 
// 说明：
// 
// 逆复正弦：
// 2 
// w=-i clog（iz+csqrt（1-z））。
// 
// casin（z）=-i casinh（iz）
// 
// 精度：
// 
// 相对误差：
// 算术域#试验峰值均方根
// DEC-10，+10 10100 2.1e 15 3.4e-16 
// 对于接近零的z，可以观察到更大的相对误差。
// 也由csin（casin（z））=z测试。

// Asin返回x的反正弦。
func Asin(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case im == 0 && math.Abs(re) <= 1:
		return complex(math.Asin(re), im)
	case re == 0 && math.Abs(im) <= 1:
		return complex(re, math.Asinh(im))
	case math.IsNaN(im):
		switch {
		case re == 0:
			return complex(re, math.NaN())
		case math.IsInf(re, 0):
			return complex(math.NaN(), re)
		default:
			return NaN()
		}
	case math.IsInf(im, 0):
		switch {
		case math.IsNaN(re):
			return x
		case math.IsInf(re, 0):
			return complex(math.Copysign(math.Pi/4, re), im)
		default:
			return complex(math.Copysign(0, re), im)
		}
	case math.IsInf(re, 0):
		return complex(math.Copysign(math.Pi/2, re), math.Copysign(re, im))
	}
	ct := complex(-imag(x), real(x)) // i*x 
	xx := x * x
	x1 := complex(1-real(xx), -imag(xx)) // 1-x*x 
	x2 := Sqrt(x1)                       // x2=sqrt（1-x*x）
	w := Log(ct + x2)
	return complex(imag(w), -real(w)) // -i*w 
}

// Asinh返回x的反双曲正弦。
func Asinh(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case im == 0 && math.Abs(re) <= 1:
		return complex(math.Asinh(re), im)
	case re == 0 && math.Abs(im) <= 1:
		return complex(re, math.Asin(im))
	case math.IsInf(re, 0):
		switch {
		case math.IsInf(im, 0):
			return complex(re, math.Copysign(math.Pi/4, im))
		case math.IsNaN(im):
			return x
		default:
			return complex(re, math.Copysign(0.0, im))
		}
	case math.IsNaN(re):
		switch {
		case im == 0:
			return x
		case math.IsInf(im, 0):
			return complex(im, re)
		default:
			return NaN()
		}
	case math.IsInf(im, 0):
		return complex(math.Copysign(im, re), math.Copysign(math.Pi/2, im))
	}
	xx := x * x
	x1 := complex(1+real(xx), imag(xx)) // 1+x*x*x 
}

// 
// 说明：
// 
// w=arccos z=PI/2-Arcin z.
// 
// 精度：
// 
// 相对误差：
// 算术域#试验峰值均方根
// DEC-10，+10 5200 1.6e-15 2.8e-16 
// IEEE-10，+10 30000 1.8e-14 2.2e-15 

// Acos返回x的反余弦。
func Acos(x complex128) complex128 {
	w := Asin(x)
	return complex(math.Pi/2-real(w), -imag(w))
}

// Acosh返回x的反双曲余弦。
func Acosh(x complex128) complex128 {
	if x == 0 {
		return complex(0, math.Copysign(math.Pi/2, imag(x)))
	}
	w := Acos(x)
	if imag(w) <= 0 {
		return complex(-imag(w), real(w)) // i*w 
	}
	return complex(imag(w), -real(w)) // -i*w 
}

// 复圆弧切线
// 
// DESCRIPTION:
// 
// 然后
// 1（2x）
// Re w=-arctan（--------------）+k PI 
// 2（2）
// （1-x-y）
// 4（2）
// （x+（y-1））
// 
// /其中k为任意整数。
// 
// catan（z）=-i catanh（iz）。
// 
// 准确度：
// 
// 相对误差：
// 算术域#试验峰值rms 
// DEC-10，+10 5900 1.3e-16 7.8e-18 
// 检查卡坦（ctan（z））=z，带| x |和| y |<PI/2，
// 峰值相对误差1.5e-16，均方根相对误差
// 2.9e-17。另请参见clog（）。

// Atan返回x的反切线。
func Atan(x complex128) complex128 {
	switch re, im := real(x), imag(x); {
	case im == 0:
		return complex(math.Atan(re), im)
	case re == 0 && math.Abs(im) <= 1:
		return complex(re, math.Atanh(im))
	case math.IsInf(im, 0) || math.IsInf(re, 0):
		if math.IsNaN(re) {
			return complex(math.NaN(), math.Copysign(0, im))
		}
		return complex(math.Copysign(math.Pi/2, re), math.Copysign(0, im))
	case math.IsNaN(re) || math.IsNaN(im):
		return NaN()
	}
	x2 := real(x) * real(x)
	a := 1 - x2 - imag(x)*imag(x)
	if a == 0 {
		return NaN()
	}
	t := 0.5 * math.Atan2(2*real(x), a)
	w := reducePi(t)

	t = imag(x) - 1
	b := x2 + t*t
	if b == 0 {
		return NaN()
	}
	t = imag(x) + 1
	c := (x2 + t*t) / b
	return complex(w, 0.25*math.Log(c))
}

// Atanh返回x的反双曲正切。
func Atanh(x complex128) complex128 {
	z := complex(-imag(x), real(x)) // z=i*x 
	z = Atan(z)
	return complex(imag(z), -real(z)) // z=-i*z 
}
